﻿#pragma once

#include <chrono>
#include <cstdint>
#include <stdexcept>
#include <string>

namespace asycipc {

enum class SessionState {
  kCreated,
  kNegotiating,
  kActive,
  kDraining,
  kClosed,
  kError,
};

class SessionContext {
 public:
  SessionContext();

  void SetSessionId(std::string id);
  const std::string& session_id() const noexcept { return session_id_; }

  SessionState state() const noexcept { return state_; }
  void TransitionTo(SessionState next_state);

  uint64_t NextSendSeq();
  void AckReceived(uint64_t seq);
  uint64_t expected_recv_seq() const noexcept { return expected_recv_seq_; }
  void RegisterInbound(uint64_t seq);

  void Touch();
  std::chrono::steady_clock::time_point last_activity() const noexcept {
    return last_activity_;
  }

 private:
  std::string session_id_;
  SessionState state_ = SessionState::kCreated;
  uint64_t next_send_seq_ = 1;
  uint64_t last_acked_seq_ = 0;
  uint64_t expected_recv_seq_ = 1;
  std::chrono::steady_clock::time_point last_activity_;
};

class SessionStateError : public std::runtime_error {
 public:
  using std::runtime_error::runtime_error;
};

}  // namespace asycipc
